﻿using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ZxZOnlineExam.Dtos.Exam;
using ZxZOnlineExam.Dtos.Question;
using ZxZOnlineExam.Dtos.ZxZUser;
using ZxZOnlineExam.IService;
using ZxZOnlineExam.Models;
using ZxZOnlineExam.WebApi.Tools.Pagination;

namespace ZxZOnlineExam.WebApi.Controllers
{
    /// <summary>
    /// Exam控制器，在此控制器中集成了ExamToStudent、ExamToQuestion、AnswerSheet、Score、WrongQuestion功能
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    //[Authorize]
    public class ExamController : ControllerBase
    {
        private readonly IMapper _mapper;
        private readonly NLog.ILogger _logger;
        private readonly IExamService _examService;
        private readonly IExamToQuestionService _examToQuestionService;
        private readonly IExamToStudentService _examToStudentService;
        private readonly IAnswerSheetService _answerSheetService;
        private readonly IScoreService _scoreService;
        private readonly IWrongQuestionRecordService _wrongQuestionRecordService;

        //引入级联关系中要用到的Service
        private readonly ISubjectService _subjectService;
        private readonly IQuestionService _questionService;
        private readonly IQuestionOptionService _questionOptionService;

        private readonly UserManager<ZxZUser> _userManager;

        public ExamController(
            IMapper mapper,
            //NLog.ILogger logger, 
            IExamService examService, 
            IExamToQuestionService examToQuestionService, 
            IExamToStudentService examToStudentService, 
            IAnswerSheetService answerSheetService, 
            IScoreService scoreService, 
            IWrongQuestionRecordService wrongQuestionRecordService, 
            ISubjectService subjectService, 
            IQuestionService questionService, 
            IQuestionOptionService questionOptionService, 
            UserManager<ZxZUser> userManager)
        {
            _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
            _logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
            _examService = examService ?? throw new ArgumentNullException(nameof(examService));
            _examToQuestionService = examToQuestionService ?? throw new ArgumentNullException(nameof(examToQuestionService));
            _examToStudentService = examToStudentService ?? throw new ArgumentNullException(nameof(examToStudentService));
            _answerSheetService = answerSheetService ?? throw new ArgumentNullException(nameof(answerSheetService));
            _scoreService = scoreService ?? throw new ArgumentNullException(nameof(scoreService));
            _wrongQuestionRecordService = wrongQuestionRecordService ?? throw new ArgumentNullException(nameof(wrongQuestionRecordService));
            _subjectService = subjectService ?? throw new ArgumentNullException(nameof(subjectService));
            _questionService = questionService ?? throw new ArgumentNullException(nameof(questionService));
            _questionOptionService = questionOptionService ?? throw new ArgumentNullException(nameof(questionOptionService));
            _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));

            _logger.Debug("Exam Controller begin to work");
        }

        # region Get
        //此处的Get包括拿到Exam下的所有信息：Student、Question等
        public async Task<ExamDto> GetAsync(Guid id)
        {
            //if (!await _examService.IsExsitedAsync(id))
            //{
            //    
            //}
            //拿到基本信息
            var result = await _examService.GetSingleAsync(id);
            if (result==null)
            {
                throw new NullReferenceException();
            }
            var examDto = _mapper.Map<ExamDto>(result);
            //拿到Student
            var examToStudents = await _examToStudentService.GetAsync(s => s.ExamId == examDto.Id);
            foreach (var item in examToStudents)
            {
                //var student = await _userManager.FindByIdAsync(item.ZxZUserId);
                //其实可以通过 Include直接拿到，不用再单独找一次
                var studentDto = _mapper.Map<ZxZUserDto>(item.ZxZUser);
                examDto.Students.Add(studentDto);
            }
            //拿到Question
            var examToQuestions = await _examToQuestionService.GetAsync(q => q.ExamId == examDto.Id);
            foreach (var item in examToQuestions)
            {
                var questionDto = _mapper.Map<QuestionDto>(item.Question);
                examDto.QuestionDtos.Add(questionDto);
            }
            return examDto;
        }

        /// <summary>
        /// 条件查询
        /// </summary>
        /// <returns></returns>
        public async Task<List<ExamDto>> GetAsync(ExamDtoFroQuery examDtoFroQuery)
        {
            List<ExamDto> examDtos = new List<ExamDto>();
            var result = (await _examService.GetAsync()).AsQueryable();//延迟查询
            //判断查询条件，依次进行查询
            //级联查询：比如说查询某个学生参加了哪一些考试
            if (String.IsNullOrEmpty(examDtoFroQuery.StudentId.ToString()))
            {
                var examToStudents = await _examToStudentService.GetAsync(e => e.ZxZUserId == examDtoFroQuery.StudentId);
                //然后根据ExamToStudent对象拿到ExamId,然后拿到指定的Exams
                List<Exam> exams = new List<Exam>();
                foreach (var item in examToStudents)
                {
                    exams.Add(await _examService.GetSingleAsync(item.Id));
                }
                result = exams.AsQueryable();
            }
            //基础查询
            if (String.IsNullOrEmpty(examDtoFroQuery.Name))
            {
                result = result.Where(e => e.Name.Contains(examDtoFroQuery.Name));
            }
            if (String.IsNullOrEmpty(examDtoFroQuery.ExamTime.ToString()))
            {
                result = result.Where(e => e.ExamTime==examDtoFroQuery.ExamTime);
            }
            if (String.IsNullOrEmpty(examDtoFroQuery.DeadLineTime.ToString()))
            {
                result = result.Where(e => e.DeadLineTime.Equals(examDtoFroQuery.DeadLineTime));
            }
            if (String.IsNullOrEmpty(examDtoFroQuery.SubjectId.ToString()))
            {
                result = result.Where(e => e.SubjectId==examDtoFroQuery.SubjectId);
            }
            if (String.IsNullOrEmpty(examDtoFroQuery.ZxzUserId.ToString()))
            {
                result = result.Where(e => e.ZxzUserId == examDtoFroQuery.ZxzUserId);
            }
            var finallyResult = result.ToList();
            //再用Get（id）方法将其转化为要返回的集合对象
            foreach (var item in finallyResult)
            {
                examDtos.Add(await GetAsync(item.Id));
            }
            return examDtos;           
        }

        /// <summary>
        /// Get Single by Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<IActionResult> GetSingle([FromRoute]Guid id)
        {
            try
            {
                var result = await GetAsync(id);
            }
            catch (Exception ex)
            {
                _logger.Debug(ex.Message);
                return NotFound();
            }
            return Ok();
        }

        /// <summary>
        /// Get Multiple By Query And Paged
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetMultiple([FromBody]ExamDtoFroQuery examDtoFroQuery,[FromQuery]Pagination pagination)
        {
            try
            {
                var result = await GetAsync(examDtoFroQuery);
                pagination.Total = result.Count;
                pagination.Data = result.Skip((pagination.PageIndex - 1) * pagination.PageSize).Take(pagination.PageSize);
            }
            catch (Exception ex)
            {
                _logger.Debug(ex.Message);
                return NotFound();
            }
            return Ok(pagination);
        }
        #endregion
    }
}
